package cn.iocoder.yudao.module.picturebook.service.classcheckin;


import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.book.BookDO;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.classmember.ClassMemberDO;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.concern.ConcernDO;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.user.PBUserDO;
import cn.iocoder.yudao.module.picturebook.dal.mysql.classmember.ClassMemberMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.concern.ConcernMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.readingrecord.ReadingRecordMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.user.PBUserMapper;
import cn.iocoder.yudao.module.picturebook.service.book.BookService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;


import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.picturebook.controller.admin.classcheckin.vo.*;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.classcheckin.ClassCheckinDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.picturebook.dal.mysql.classcheckin.ClassCheckinMapper;

/**
 * 班级打卡记录 Service 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@Service
@Validated
public class ClassCheckinServiceImpl implements ClassCheckinService {

    @Resource
    private ClassCheckinMapper classCheckinMapper;

    @Resource
    private BookService bookService;

    @Resource
    private PBUserMapper userMapper;

    @Resource
    private ConcernMapper concernMapper;

    @Resource
    private ReadingRecordMapper readingRecordMapper;
    @Resource
    private ClassMemberMapper classMemberMapper;

    // ... existing code ...
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long createClassCheckin(ClassCheckinSaveReqVO createReqVO) {
        // 参数校验
        if (createReqVO == null) {
            log.warn("[createClassCheckin][请求参数不能为空]");
            return null;
        }
        if (createReqVO.getUserId() == null || createReqVO.getUserId() <= 0) {
            log.warn("[createClassCheckin][用户ID无效]");
            return null;
        }

        try {
            // 转换请求参数
            ClassCheckinDO classCheckin = BeanUtils.toBean(createReqVO, ClassCheckinDO.class);

            // 设置打卡日期
            LocalDate today = LocalDate.now();
            classCheckin.setCheckinDate(today);

            // 处理班级ID为空的情况
            if (classCheckin.getClassId() == null) {
                classCheckin.setClassId(0L);
            }

            // 获取今日阅读记录并序列化
            List<Integer> bookIds = readingRecordMapper.getRecordByUserId(classCheckin.getUserId(), today);
            classCheckin.setBookId(JsonUtils.toJsonString(bookIds)); // 使用统一的 JSON 工具类

            // 查询是否存在旧记录
            ClassCheckinDO oldClassCheckin = classCheckinMapper.getByUserIdAndDate(classCheckin.getUserId(), today);
            log.info("createClassCheckin oldClassCheckin: {}", oldClassCheckin);
            if (oldClassCheckin != null) {
                classCheckinMapper.deleteByCheckinId(oldClassCheckin.getId());
            }

            // 插入新记录
            classCheckinMapper.insert(classCheckin);

            // 返回ID
            return classCheckin.getId();
        } catch (Exception e) {
            // 记录日志并返回null
            log.error("[createClassCheckin] 创建打卡记录失败", e);
            return null;
        }
    }


    @Override
    public void updateClassCheckin(ClassCheckinSaveReqVO updateReqVO) {
        // 参数校验
        if (updateReqVO == null) {
            log.warn("[updateClassCheckin][请求参数不能为空]");
            return;
        }
        if (updateReqVO.getId() == null) {
            log.warn("[updateClassCheckin][打卡记录ID不能为空]");
            return;
        }

        // 校验存在
        if (classCheckinMapper.selectById(updateReqVO.getId()) == null) {
            log.warn("[updateClassCheckin][打卡记录不存在，ID：{}]", updateReqVO.getId());
            return;
        }
        // 更新
        ClassCheckinDO updateObj = BeanUtils.toBean(updateReqVO, ClassCheckinDO.class);
        classCheckinMapper.updateById(updateObj);
    }

    @Override
    public void deleteClassCheckin(Long id) {
        // 参数校验
        if (id == null) {
            log.warn("[deleteClassCheckin][打卡记录ID不能为空]");
            return;
        }

        // 校验存在
        if (classCheckinMapper.selectById(id) == null) {
            log.warn("[deleteClassCheckin][打卡记录不存在，ID：{}]", id);
            return;
        }
        // 删除
        classCheckinMapper.deleteById(id);
    }

    @Override
    public void deleteClassCheckinListByIds(List<Long> ids) {
        // 参数校验
        if (ids == null || ids.isEmpty()) {
            log.warn("[deleteClassCheckinListByIds][打卡记录ID列表不能为空]");
            return;
        }

        // 删除
        classCheckinMapper.deleteByIds(ids);
    }


    private void validateClassCheckinExists(Long id) {
        // 参数校验
        if (id == null) {
            log.warn("[validateClassCheckinExists][打卡记录ID不能为空]");
            return;
        }

        if (classCheckinMapper.selectById(id) == null) {
            log.warn("[validateClassCheckinExists][打卡记录不存在，ID：{}]", id);
            return;
        }
    }

    @Override
    public ClassCheckinDO getClassCheckin(Long id) {
        // 参数校验
        if (id == null) {
            log.warn("[getClassCheckin][打卡记录ID不能为空]");
            return null;
        }

        return classCheckinMapper.selectById(id);
    }

    /**
     * 根据分页请求获取班级签到信息
     *
     * @param pageReqVO 分页请求对象，包含分页参数和筛选条件
     * @return 返回一个分页结果对象，包含签到信息列表和总记录数
     */
    @Override
    public PageResult<ClassCheckinRespVO> getClassCheckinPage(ClassCheckinPageReqVO pageReqVO) {
        // 参数校验
        if (pageReqVO == null) {
            log.warn("[getClassCheckinPage][分页请求参数不能为空]");
            return PageResult.empty();
        }

        // 从数据库中查询分页的签到记录
        PageResult<ClassCheckinDO> pageResult = classCheckinMapper.selectPage(pageReqVO);
        if (pageResult == null) {
            return PageResult.empty();
        }

        // 初始化返回结果对象
        PageResult<ClassCheckinRespVO> result = new PageResult<>();
        result.setList(new ArrayList<>());
        result.setTotal(pageResult.getTotal());

        // 遍历查询到的签到记录
        for (ClassCheckinDO classCheckinDO : pageResult.getList()) {
            if (classCheckinDO == null) {
                continue;
            }

            String bookIdStr = classCheckinDO.getBookId();

            // 如果书籍 ID 字符串为空，则直接转换对象并设置空的书籍列表
            if (StringUtils.isEmpty(bookIdStr)) {
                result.getList().add(BeanUtils.toBean(classCheckinDO, ClassCheckinRespVO.class).setBooks(Collections.emptyList()));
                continue;
            }

            // 提取合法的书籍 ID
            List<Integer> bookIdList = parseBookIds(bookIdStr);

            // 如果解析后的书籍 ID 列表为空，同样直接转换对象并设置空的书籍列表
            if (bookIdList.isEmpty()) {
                result.getList().add(BeanUtils.toBean(classCheckinDO, ClassCheckinRespVO.class).setBooks(Collections.emptyList()));
                continue;
            }

            try {
                // 根据书籍 ID 列表查询对应的书籍信息
                List<BookDO> bookList = bookService.selectByIds(convertToLongList(bookIdList));
                // 将签到记录和对应的书籍信息添加到结果列表中
                result.getList().add(BeanUtils.toBean(classCheckinDO, ClassCheckinRespVO.class).setBooks(bookList));
            } catch (Exception e) {
                // 记录日志并设置空列表，避免整个接口失败
                log.warn("[getClassCheckinPage] 书籍查询失败，bookIds: {}", bookIdList, e);
                result.getList().add(BeanUtils.toBean(classCheckinDO, ClassCheckinRespVO.class).setBooks(Collections.emptyList()));
            }
        }

        // 返回处理后的分页结果
        return result;
    }


    private List<Integer> parseBookIds(String bookIdStr) {
        if (bookIdStr == null || bookIdStr.isEmpty()) {
            return Collections.emptyList();
        }

        try {
            return Arrays.stream(bookIdStr.replaceAll("[^0-9,]", "").split(","))
                    .filter(s -> !s.isEmpty())
                    .map(Integer::parseInt)
                    .distinct()
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.warn("[parseBookIds] 解析书籍ID失败，bookIdStr: {}", bookIdStr, e);
            return Collections.emptyList();
        }
    }

    private List<Long> convertToLongList(List<Integer> intList) {
        if (intList == null || intList.isEmpty()) {
            return Collections.emptyList();
        }

        List<Long> longList = new ArrayList<>(intList.size());
        for (Integer id : intList) {
            if (id != null) {
                longList.add(Long.valueOf(id));
            }
        }
        return longList;
    }


    @Override
    public PageResult<CheckinRespAllData> listAll(ClassCheckinPageReqVO pageReqVO, Long userId) {
        // 参数校验
        if (pageReqVO == null || userId == null || userId <= 0) {
            log.warn("[listAll] 参数校验失败，pageReqVO: {}, userId: {}", pageReqVO, userId);
            return new PageResult<>(Collections.emptyList(), 0L);
        }

        // 查询打卡记录
        PageResult<ClassCheckinDO> classCheckinDOList = classCheckinMapper.selectPage(pageReqVO);
        if (classCheckinDOList == null || classCheckinDOList.getList() == null) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }

        List<CheckinRespAllData> result = new ArrayList<>();

        LocalDateTime now = LocalDateTime.now(); // 统一时间，避免多次调用

        for (ClassCheckinDO classCheckinDO : classCheckinDOList.getList()) {
            if (classCheckinDO == null) {
                continue;
            }

            CheckinRespAllData checkinRespAllData = new CheckinRespAllData();

            // 设置基础信息
            checkinRespAllData.setCheckinId(classCheckinDO.getId());
            checkinRespAllData.setUserId(classCheckinDO.getUserId());

            // 设置用户名，处理用户不存在的情况
            Long targetUserId = classCheckinDO.getUserId();
            String realName = "";
            if (targetUserId != null && targetUserId > 0) {
                PBUserDO user = userMapper.selectById(targetUserId);
                if (user != null && user.getRealName() != null) {
                    realName = user.getRealName();
                }
            }
            checkinRespAllData.setUserName(realName);

            // 设置打卡时间描述
            LocalDateTime updateTime = classCheckinDO.getUpdateTime();
            if (updateTime != null && !updateTime.isAfter(now)) {
                Duration duration = Duration.between(updateTime, now);
                if (duration.toMinutes() < 60) {
                    checkinRespAllData.setTimeAgo(duration.toMinutes() + "分钟前打卡");
                } else if (duration.toHours() < 24) {
                    checkinRespAllData.setTimeAgo(duration.toHours() + "小时前");
                } else if (duration.toDays() < 7) {
                    checkinRespAllData.setTimeAgo(duration.toDays() + "天前");
                } else if (duration.toDays() < 30) {
                    checkinRespAllData.setTimeAgo(duration.toDays() / 7 + "周前");
                } else if (duration.toDays() < 365) {
                    checkinRespAllData.setTimeAgo(duration.toDays() / 30 + "个月前");
                } else {
                    checkinRespAllData.setTimeAgo("很久以前");
                }
            } else {
                checkinRespAllData.setTimeAgo("未知时间");
            }

            // 设置关注状态
            if (userId.equals(targetUserId)) {
                checkinRespAllData.setIsConcern(0);
            } else {
                ConcernDO concernDO = null;
                if (targetUserId != null && targetUserId > 0) {
                    concernDO = concernMapper.selectByUserIdAndConcernId(userId, targetUserId);
                }
                checkinRespAllData.setIsConcern(concernDO != null ? 2 : 1);
            }

            // 设置打卡心得
            checkinRespAllData.setContent(classCheckinDO.getContent());

            // 设置打卡天数
            int dayCount = 0;
            if (targetUserId != null && targetUserId > 0) {
                try {
                    dayCount = classCheckinMapper.getDayCount(targetUserId);
                } catch (Exception e) {
                    log.warn("[listAll] 获取打卡天数失败，userId: {}", targetUserId, e);
                }
            }
            checkinRespAllData.setDay(dayCount);

            // 设置打卡时间
            checkinRespAllData.setCheckinTime(classCheckinDO.getUpdateTime());

            // 解析书籍 ID
            String BookIds = classCheckinDO.getBookId();
            List<Integer> Books = new ArrayList<>();
            if (BookIds != null && !BookIds.trim().isEmpty()) {
                try {
                    Books = Arrays.stream(BookIds.replaceAll("[^0-9,]", "").split(","))
                            .filter(s -> !s.isEmpty())
                            .map(Integer::parseInt)
                            .collect(Collectors.toList());
                } catch (Exception e) {
                    log.warn("[listAll] 解析书籍ID失败，BookIds: {}", BookIds, e);
                }
            }

            // 查询书籍信息并设置
            List<BookDO> bookList = new ArrayList<>();
            int bookCount = 0;
            for (Integer bookId : Books) {
                if (bookId != null && bookId > 0) {
                    BookDO book = bookService.selectById(Long.valueOf(bookId));
                    if (book != null) {
                        bookList.add(book);
                    }
                }
            }
            bookCount = bookList.size();

            checkinRespAllData.setBooks(bookList);
            checkinRespAllData.setBookCount(bookCount);

            result.add(checkinRespAllData);
        }

        return new PageResult<>(result, (long) result.size());
    }


    @Override
    public PageResult<CheckinRespAllData> listAllByConcern(ClassCheckinPageReqVO pageReqVO, Long userId) {
        // 参数校验
        if (pageReqVO == null || userId == null || userId <= 0) {
            log.warn("[listAllByConcern] 参数校验失败，pageReqVO: {}, userId: {}", pageReqVO, userId);
            return PageResult.empty();
        }

        //先获取被关注的人的id
        List<Long> concernIds = concernMapper.selectByUserId(userId);
        if (concernIds == null) {
            concernIds = Collections.emptyList();
        }

        List<CheckinRespAllData> result = new ArrayList<>();
        //循环获取被关注的人的打卡记录
        for (Long concernId : concernIds) {
            if (concernId != null && concernId > 0) {
                pageReqVO.setUserId(concernId);
                PageResult<CheckinRespAllData> pageResult = listAll(pageReqVO, userId);
                if (pageResult != null && pageResult.getList() != null) {
                    result.addAll(pageResult.getList());
                }
            }
        }
        //对result进行排序根据update
        result.sort(Comparator.comparing(CheckinRespAllData::getCheckinTime, Comparator.nullsFirst(Comparator.reverseOrder())));
        return new PageResult<>(result, (long) result.size());
    }

    @Override
    public Boolean checkCanCheckin(Long userId) {
        // 用户ID校验
        if (userId == null || userId <= 0) {
            log.warn("[checkCanCheckin] 用户ID无效: {}", userId);
            return false; // 无效用户ID，禁止打卡
        }

        LocalDate now = LocalDate.now();

        // 获取今日打卡记录
        ClassCheckinDO isCheckin = classCheckinMapper.getByUserIdAndDate(userId, now);

        // 获取今日阅读记录数量
        int count = 0;
        try {
            count = readingRecordMapper.getTodayCount(userId, now);
        } catch (Exception e) {
            // 数据库异常，默认不允许打卡
            log.error("[checkCanCheckin] 获取阅读记录数量失败，userId: {}", userId, e);
            return false;
        }

        if (count == 0) {
            return false; // 没有阅读记录，不允许打卡
        }

        if (isCheckin == null) {
            return true; // 无打卡记录，允许打卡
        }

        // 获取并解析书籍 ID 字符串
        String bookIdStr = isCheckin.getBookId();

        // 空值或空白字符串，视为未设置，允许打卡
        if (bookIdStr == null || bookIdStr.trim().isEmpty()) {
            return true;
        }

        // 清理并提取合法的书籍 ID
        List<Integer> planBook = new ArrayList<>();
        try {
            planBook = Arrays.stream(bookIdStr.replaceAll("[^0-9,]", "").split(","))
                    .filter(s -> !s.isEmpty())
                    .map(Integer::parseInt)
                    .distinct()
                    .collect(Collectors.toList());
        } catch (Exception e) {
            // 解析失败，视为无效书籍ID，允许打卡（避免因格式错误导致无法打卡）
            log.warn("[checkCanCheckin] 解析书籍ID失败，bookIdStr: {}", bookIdStr, e);
            return true;
        }

        int bookCount = planBook.size();

        // 判断是否允许打卡
        return bookCount != count;
    }


    @Override
    public CheckinClassRespVO listAllClassCheckin(ClassCheckinPageReqVO pageReqVO) {
        // 参数校验
        if (pageReqVO == null || pageReqVO.getClassId() == null || pageReqVO.getClassId() <= 0) {
            log.warn("[listAllClassCheckin] 参数校验失败，pageReqVO: {}", pageReqVO);
            return new CheckinClassRespVO("0/0", Collections.emptyList());
        }

        // 查询班级成员列表
        List<ClassMemberDO> classMemberList = classMemberMapper.getClassAllMemberByClassId(pageReqVO.getClassId());
        if (classMemberList == null) {
            classMemberList = Collections.emptyList();
        }

        List<CheckinRespAllData> checkinRespAllDataList = new ArrayList<>();

        // 获取当前时间，避免多次调用 LocalDate.now()
        LocalDate now = LocalDate.now();

        // 循环获取每个学生的打卡记录
        for (ClassMemberDO classMemberDO : classMemberList) {
            if (classMemberDO == null || classMemberDO.getUserId() == null || classMemberDO.getUserId() <= 0) {
                continue; // 跳过非法或空的成员
            }

            pageReqVO.setClassId(null);
            pageReqVO.setUserId(classMemberDO.getUserId());

            PageResult<CheckinRespAllData> checkinRespAllDataPageResult = listAll(pageReqVO, classMemberDO.getUserId());

            if (checkinRespAllDataPageResult != null && checkinRespAllDataPageResult.getList() != null) {
                checkinRespAllDataList.addAll(checkinRespAllDataPageResult.getList());
            }
        }

        // 对结果进行排序
        checkinRespAllDataList.sort(Comparator.comparing(CheckinRespAllData::getCheckinTime, Comparator.nullsFirst(Comparator.reverseOrder())));

        // 统计打卡人数
        int checkinCount = 0;
        for (ClassMemberDO classMemberDO : classMemberList) {
            if (classMemberDO == null || classMemberDO.getUserId() == null || classMemberDO.getUserId() <= 0) {
                continue;
            }

            ClassCheckinDO checkinDO = classCheckinMapper.getByUserIdAndDate(classMemberDO.getUserId(), now);
            if (checkinDO != null) {
                checkinCount++;
            }
        }

        // 拼接人数
        String percent = checkinCount + "/" + classMemberList.size();

        return new CheckinClassRespVO(percent, checkinRespAllDataList);
    }

    @Override
    public CheckinCalendarVO getUserCheckinCalendar(Long userId) {
        // 参数校验
        if (userId == null || userId <= 0) {
            log.warn("[getUserCheckinCalendar] 用户ID无效: {}", userId);
            return new CheckinCalendarVO();
        }

        //获取用户的所以打卡记录
        List<ClassCheckinDO> checkinList = classCheckinMapper.getByUser(userId);
        if (checkinList == null) {
            checkinList = Collections.emptyList();
        }

        //获取里面的打卡时间
        List<LocalDate> checkinDates = checkinList.stream()
                .filter(Objects::nonNull)
                .map(ClassCheckinDO::getCheckinDate)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        //创建一个Map，用于存储打卡时间
        Map<String, List<Integer>> checkinDatesMap = new HashMap<>();
        //将同一年同一个月封装成一个map集合
        for (LocalDate checkinDate : checkinDates) {
            String key = checkinDate.getYear() + "-" + checkinDate.getMonthValue();
            checkinDatesMap.computeIfAbsent(key, k -> new ArrayList<>()).add(checkinDate.getDayOfMonth());
        }
        //创建一个返回对象
        CheckinCalendarVO checkinCalendarVO = new CheckinCalendarVO();
        checkinCalendarVO.setPunchDays(null);
        checkinCalendarVO.setPunchDaysMap(checkinDatesMap);
        return checkinCalendarVO;
    }
// ... existing code ...


}